#include "simstruc.h"

static int_T nInPortNums = 7;
static int_T nInPortNumWidth[7] = {1,1,1,1,1,1,1};
static int_T nOutPortNums = 1;
static int_T nOutPortNumWidth[1] = {6};
static int_T nDiscretNums = 0;

int_T simGetInPortNums(void) {
    return nInPortNums;
}
int_T simGetInPortNumWidth(int port) {
    return nInPortNumWidth[port];
}
int_T simGetOutPortNums(void) {
    return nOutPortNums;
}
int_T simGetOutPortNumWidth(int port) {
    return nOutPortNumWidth[port];
}

#define IN_PhaseA      *ssGetInputPortRealSignalPtrs(S, 0)[0]
#define IN_PhaseB      *ssGetInputPortRealSignalPtrs(S, 1)[0]
#define IN_PhaseC      *ssGetInputPortRealSignalPtrs(S, 2)[0]
#define IN_Module_Wave *ssGetInputPortRealSignalPtrs(S, 3)[0]
#define IN_DeadTime    *ssGetInputPortRealSignalPtrs(S, 4)[0]
#define IN_Enabled     *ssGetInputPortRealSignalPtrs(S, 5)[0]
#define IN_PWMMode     *ssGetInputPortRealSignalPtrs(S, 6)[0]
#define Out_PhaseA_H 0
#define Out_PhaseA_L 1
#define Out_PhaseB_H 2
#define Out_PhaseB_L 3
#define Out_PhaseC_H 4
#define Out_PhaseC_L 5

#define PWM_MODE0 0
#define PWM_MODE1 1

static int_T     pwm_mode;
static boolean_T Result[6];
static boolean_T pwm_record[6];
static boolean_T pwmOut[6];
static int_T     pwm_delay[6];

static void getPwmDuty(real_T wave, real_T pwm_value, boolean_T *h, boolean_T *l) {
    if (wave >= pwm_value) {
        *h = (pwm_mode == PWM_MODE0)?true:false;
        *l = (pwm_mode == PWM_MODE0)?false:true;
    }else {
        *h = (pwm_mode == PWM_MODE0)?false:true;
        *l = (pwm_mode == PWM_MODE0)?true:false;
    }
}

static void deadTimeDelay(int_T bridge, int_T deadTime) {
    if (Result[bridge] && !pwm_record[bridge]) {
        pwm_delay[bridge] = deadTime;
        pwm_record[bridge] = Result[bridge];
    }else if (!Result[bridge] && pwm_record[bridge]){
        pwm_delay[bridge] = 0;
        pwm_record[bridge] = Result[bridge];    
    }else {
        pwm_record[bridge] = Result[bridge]; 
    }

    if (pwm_delay[bridge] == 0) {
        pwmOut[bridge] = pwm_record[bridge];
    }else {
        pwm_delay[bridge]--;
    }
}


void sim_sfunc_init(SimStruct *S) {
    memset(Result, 0, sizeof(Result));
    memset(pwm_record, 0, sizeof(pwm_record));
    memset(pwmOut, 0, sizeof(pwmOut));
    memset(pwm_delay, 0, sizeof(pwm_delay));
}

void sim_sfunc_terminate(SimStruct *S) {
    ssPrintf("timer Stop\n");
}

void sim_sfunc_core(SimStruct *S) {
    pwm_mode = (int_T)IN_PWMMode;    
    if (IN_Enabled != 0) {
        getPwmDuty(IN_Module_Wave, IN_PhaseA, &Result[Out_PhaseA_H], &Result[Out_PhaseA_L]);
        getPwmDuty(IN_Module_Wave, IN_PhaseB, &Result[Out_PhaseB_H], &Result[Out_PhaseB_L]);
        getPwmDuty(IN_Module_Wave, IN_PhaseC, &Result[Out_PhaseC_H], &Result[Out_PhaseC_L]);

        deadTimeDelay(Out_PhaseA_H, IN_DeadTime);
        deadTimeDelay(Out_PhaseA_L, IN_DeadTime);
        deadTimeDelay(Out_PhaseB_H, IN_DeadTime);
        deadTimeDelay(Out_PhaseB_L, IN_DeadTime);
        deadTimeDelay(Out_PhaseC_H, IN_DeadTime);
        deadTimeDelay(Out_PhaseC_L, IN_DeadTime);
    }else {
        for (int i = 0; i < 6; i++) {
            pwmOut[i] = 0;
        }
    }
}

void sim_sfunc_output(SimStruct *S) {
    boolean_T         *y    = (boolean_T *)ssGetOutputPortRealSignal(S,0);
    for (int i = 0; i < 6; i++) {
        y[i] = pwmOut[i];
    }
}